﻿/*
	Author	:	Zhou Baojing
	Email	:	zbjxb@126.com
	Date	:	2015/10/31
	Modified:	2015/11/02 This version is just for ANSI CharSet now.
*/

#include "json.h"
#include "common.h"

/**
json 	:= NVPair[,json+]
		|	array
		|	object
NVPair	:= "name":value
name 	:= [_0-9a-zA-Z]+
value	:= null | true | false | number | "string" | array | object
array	:= \[\] | [value[,value+]]
object	:= {} | {NVPair[,NVPair+]}
number	:=
*/

///////////////////////////////////////////
// Model definition

enum eJSOType
{
	eUnknownJSO,
	eNullJSO,
	eBoolJSO,
	eNumberJSO,
	eStringJSO,
	eNVPairJSO,
	eArrayJSO,
	eObjectJSO,
};

struct jsonJSO
{
	eJSOType type;
	virtual ~jsonJSO(){}
};
struct jsonNullJSO : public jsonJSO
{
	jsonNullJSO() { type = eNullJSO; }
};
struct jsonBoolJSO : jsonJSO
{
	jsonBoolJSO() { type = eBoolJSO; }
	bool value;
};
struct jsonNumberJSO : jsonJSO
{
	jsonNumberJSO() { type = eNumberJSO; }
	double value;
};
struct jsonStringJSO : jsonJSO
{
	jsonStringJSO() { type = eStringJSO; }
	std::string value;
};
struct jsonNVPairJSO : jsonJSO
{
	jsonNVPairJSO() { type = eNVPairJSO; }
	~jsonNVPairJSO() {
		delete value.first;
		delete value.second;
	}
	std::pair<jsonStringJSO*, jsonJSO*> value;
};
struct jsonArrayJSO : jsonJSO
{
	jsonArrayJSO() { type = eArrayJSO; }
	~jsonArrayJSO() {
		for (auto i = value.begin(); i != value.end(); ++i) {
			delete *i;
		}
	}
	std::vector<jsonJSO*> value;
};
struct jsonObjectJSO : jsonJSO
{
	jsonObjectJSO() { type = eObjectJSO; }
	~jsonObjectJSO() {
		for (auto i = value.begin(); i != value.end(); ++i) {
			delete *i;
		}
	}
	std::vector<jsonNVPairJSO*> value;
};

///////////////////////////////////////////
// implementation

bool jsonDocument::parse(const char* json, int count /*= -1*/)
{
	if (beforeParse(json, count)) {
		if (parseJson()) {
			afterParse();
			return true;
		}
	}
	return false;
}

void jsonDocument::scoop()
{
	bowl = pool[flag];
	++flag;
}

void jsonDocument::preview()
{
	peek_bowl = pool[flag];
}

void jsonDocument::skipWhite()
{
	preview();
	while (isspace(peek_bowl)) {
		scoop();
		preview();
	}
}

bool jsonDocument::expected(char dream)
{
	scoop();
	if (bowl == dream) {
		skipWhite();
		return true;
	}
	return false;
}

bool jsonDocument::expected(const char* dream)
{
	for (const char* p = dream; *p != 0; ++p) {
		scoop();
		if (*p == bowl) {
			continue;
		}
		return false;
	}
	skipWhite();
	return true;
}

bool jsonDocument::beforeParse(const char* json, int count /*= -1*/)
{
	if ((count == -1 && (eof_flag = strlen(json))) ||
		(eof_flag = count) > 0)
	{
		flag = 0;
		pool = json;
		skipWhite();
		return true;
	}
	return false;
}

void jsonDocument::afterParse()
{
}

bool jsonDocument::parseJson()
{
	// 先预览一下，决定下一步动作 
	preview();

	// 判断碗里的东西
	if (peek_bowl == '"') {	// NVPair[,json+]
		if (!parseNVPair()) {
			return false;
		}
	}
	else if (peek_bowl == '[') {	// array
		if (!parseArray()) {
			return false;
		}
	}
	else if (peek_bowl == '{') {	// object
		if (!parseObject()) {
			return false;
		}
	}
	else {
		return false;
	}

	auto nvpair = context();
	this->content.push_back(nvpair);

	preview();
	if (peek_bowl == ',') {
		expected(',');
		return parseJson();
	}
	else {
		return (flag == eof_flag);	// 结束解析
	}
}

bool jsonDocument::parseName()
{
	return parseString();
}

bool jsonDocument::parseValue()
{
	preview();
	if (peek_bowl == 'n') {
		return parseNull();
	}
	else if (peek_bowl == 't') {
		return parseTrue();
	}
	else if (peek_bowl == 'f') {
		return parseFalse();
	}
	else if (isdigit(peek_bowl) || peek_bowl == '-') {
		return parseNumber();
	}
	else if (peek_bowl == '"') {
		return parseString();
	}
	else if (peek_bowl == '[') {
		return parseArray();
	}
	else if (peek_bowl == '{') {
		return parseObject();
	}
	else {
		return false;
	}
}

bool jsonDocument::parseNVPair()
{
	jsonNVPairJSO* jso = new jsonNVPairJSO();
	auto gc = finally([jso]{ delete jso; });
	if (parseName()) {
		if (expected(':')) {
			if (parseValue()) {
				auto& valueContext = context();
				auto& nameContext = context();
				auto nameJSO = static_cast<jsonStringJSO*>(nameContext);
				if (nameJSO) {
					jso->value.first = nameJSO;
					jso->value.second = valueContext;
					saveContext(jso);
					gc.discard();
					return true;
				}
			}
		}
	}
	return false;
}

bool jsonDocument::parseArray()
{
	jsonArrayJSO* jso = new jsonArrayJSO();
	auto gc = finally([jso]{ delete jso; });
	if (expected('[')) {
		preview();
		if (peek_bowl != ']') {
			if (parseValue()) {
				do {
					jso->value.push_back(context());
					preview();
					if (peek_bowl != ']') {
						if (expected(',')) {
							if (parseValue()) {
								continue;
							}
							else {
								return false;
							}
						}
						else {
							return false;
						}
					}
					else {
						if (expected(']')) {
							saveContext(jso);
							gc.discard();
							return true;
						}
						else {
							return false;
						}
					}
				} while (true);
			}
			else {
				return false;
			}
		}
		else {
			if (expected(']')) {
				saveContext(jso);
				gc.discard();
				return true;
			}
			else {
				return false;
			}
		}
	}
	else {
		return false;
	}
}

bool jsonDocument::parseObject()
{
	jsonObjectJSO* jso = new jsonObjectJSO();
	auto gc = finally([jso]{ delete jso; });
	if (expected('{')) {
		preview();
		if (peek_bowl != '}') {
			if (parseNVPair()) {
				do {
					auto nvpair = static_cast<jsonNVPairJSO*>(context());
					if (nvpair) {
						jso->value.push_back(nvpair);
					}
					else {
						return false;
					}
					preview();
					if (peek_bowl != '}') {
						if (expected(',')) {
							if (parseNVPair()) {
								continue;
							}
							else {
								return false;
							}
						}
						else {
							return false;
						}
					}
					else {
						if (expected('}')) {
							saveContext(jso);
							gc.discard();
							return true;
						}
						else {
							return false;
						}
					}
				} while (true);
			}
			else {
				return false;
			}
		}
		else {
			if (expected('}')) {
				saveContext(jso);
				gc.discard();
				return true;
			}
			else {
				return false;
			}
		}
	}
	else {
		return false;
	}
}

bool jsonDocument::parseNull()
{
	if (expected("null")) {
		saveContext(new jsonNullJSO());
		return true;
	}
	return false;
}

bool jsonDocument::parseTrue()
{
	if (expected("true")) {
		jsonBoolJSO* jso = new jsonBoolJSO();
		jso->value = true;
		saveContext(jso);
		return true;
	}
	return false;
}

bool jsonDocument::parseFalse()
{
	if (expected("false")) {
		jsonBoolJSO* jso = new jsonBoolJSO();
		jso->value = false;
		saveContext(jso);
		return true;
	}
	return false;
}

bool jsonDocument::parseString()
{
	jsonStringJSO* jso = new jsonStringJSO();
	auto gc = finally([jso]{ delete jso; });
	if (expected('"')) {
		chars_buff buff(jso->value);
		do {
			preview();
			if (peek_bowl != '"') {
				if (peek_bowl == '\\') {
					// todo: 转义字符
					scoop();
					scoop();
					switch (bowl)
					{
					case 'a':
						buff.push('\a');
						break;
					case 'b':
						buff.push('\b');
						break;
					case 'f':
						buff.push('\f');
						break;
					case 'n':
						buff.push('\n');
						break;
					case 'r':
						buff.push('\r');
						break;
					case 't':
						buff.push('\t');
						break;
					case 'v':
						buff.push('\v');
						break;
					case '\\':
						buff.push('\\');
						break;
					case '\'':
						buff.push('\'');
						break;
					case '\"':
						buff.push('\"');
						break;
					case 'u':
						// four-hex-digits
						break;
					default:
						return false;
					}
					continue;
				}
				else {
					// todo: common character
					scoop();
					buff.push(bowl);
					continue;
				}
			}
			if (expected('"')) {
				saveContext(jso);
				gc.discard();
				return true;
			}
			else {
				return false;
			}
		} while (true);
	}
	return false;
}

bool jsonDocument::parseDigits(chars_buff& buff)
{
	bool isHasNoneDigit = true;

	preview();
	if (isdigit(peek_bowl)) {
		isHasNoneDigit = false;
	}

	do 
	{
		if (isdigit(peek_bowl)) {
			scoop();
			buff.push(bowl);
			preview();
		}
		else {
			return !isHasNoneDigit;
		}
	} while (true);
}

bool jsonDocument::parseNumber()
{
	jsonNumberJSO* jso = new jsonNumberJSO();
	auto gc = finally([jso]{ delete jso; });

	std::string numberStr;
	chars_buff buff(numberStr);

	preview();
	if (peek_bowl == '-') {
		scoop();
		buff.push(bowl);
		preview();
	}
	if (isdigit(peek_bowl)) {	// 第一个数字
		scoop();
		buff.push(bowl);
		preview();
		if (isdigit(peek_bowl)) {	// 第二个数字
			if (bowl == '0') {
				return false;	// 第一个数字不能是0
			}
			else {
				if (!parseDigits(buff)) {
					return false;
				}
			}
		}
		if (peek_bowl == '.') {
			scoop();
			buff.push(bowl);
			if (!parseDigits(buff)) {
				return false;
			}
		}
		if (peek_bowl == 'e' || peek_bowl == 'E') {
			scoop();
			buff.push(bowl);
			preview();
			if (peek_bowl == '+' || peek_bowl == '-') {
				scoop();
				buff.push(bowl);
				preview();
			}
			if (isdigit(peek_bowl)) {
				if (parseDigits(buff)) {
					buff.flush();
					jso->value = atof(numberStr.c_str());
					saveContext(jso);
					gc.discard();
					return true;
				}
			}
			return false;
		}

		buff.flush();
		jso->value = atof(numberStr.c_str());
		saveContext(jso);
		gc.discard();
		return true;
	}
	else {
		return false;
	}
}

jsonDocument::~jsonDocument()
{
	for (auto i = content.begin(); i != content.end(); ++i) {
		delete *i;
	}
}

